package org.tamal.servlet;

import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.tamal.Constants;
import org.tamal.HttpSession;
import org.tamal.Util;
import org.tamal.persistence.User;

/**
 * LoginServlet is used to log-in through Open Authentication v2.
 * @author Tamal Kanti Nath
 */
@WebServlet("LoginServlet")
public final class LoginServlet extends HttpServlet {

    private static final long serialVersionUID = 5099443306374469482L;
    private static final String STATE_MSG =
            "Invalid state. Only 'f' (Facebook) or 'g' (Google) are accepted.";

    private final transient Logger log = Logger.getLogger(getClass().getName());

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        String code = request.getParameter("code");
        String state = request.getParameter("state");
        if (code == null || state == null) {
            response.sendError(400, "Both code and state are required.");
            return;
        }
        if (state.length() != 1) {
            response.sendError(400, STATE_MSG);
            return;
        }
        char s = state.charAt(0);
        if (!(s == Constants.GOOGLE_STATE || s == Constants.FACEBOOK_STATE)) {
            response.sendError(400, STATE_MSG);
            return;
        }
        try {
            User user = fetchUser(code, s);
            Util.getService().login(user);
            request.getSession().setAttribute(HttpSession.USER.name(), user);
            response.sendRedirect("/");
        } catch (JSONException e) {
            log.error(e);
            response.sendError(502, e.toString());
        }
    }

    private User fetchUser(String code, char state)
        throws IOException, JSONException {
        String url = null;
        String client = null;
        String secret = null;
        if (Constants.GOOGLE_STATE == state) {
            url = Constants.GOOGLE_TOKEN;
            client = Constants.GOOGLE_ID;
            secret = Constants.GOOGLE_SECRET;
        }
        if (Constants.FACEBOOK_STATE == state) {
            url = Constants.FACEBOOK_TOKEN;
            client = Constants.FACEBOOK_ID;
            secret = Constants.FACEBOOK_SECRET;
        }
        String data = "code=" + code
                + "&redirect_uri=" + Constants.REDIRECT_URI
                + "&client_id=" + client
                + "&client_secret=" + secret
                + "&grant_type=authorization_code";
        data = Util.fetchUrl(url, data);
        log.debug(data);
        User user = new User();
        if (Constants.GOOGLE_STATE == state) {
            url = Constants.GOOGLE_URL + "?access_token="
                    + new JSONObject(data).getString("access_token");
        }
        if (Constants.FACEBOOK_STATE == state) {
            url = Constants.FACEBOOK_URL + "?" + data;
        }
        data = Util.fetchUrl(url, null);
        log.debug(data);
        JSONObject json = new JSONObject(data);
        user.setName(json.getString("name"));
        user.setEmail(json.getString("email"));
        user.setLastLogin(new Date());
        user.setProvider(state);
        return user;
    }
}
